// Copyright Epic Games, Inc. All Rights Reserved. // 版权声明，Epic Games公司版权所有

#include "LyraAbilitySystemComponent.h" // 包含Lyra能力系统组件头文件

#include "AbilitySystem/Abilities/LyraGameplayAbility.h" // 包含Lyra游戏能力类头文件
#include "AbilitySystem/LyraAbilityTagRelationshipMapping.h" // 包含Lyra能力标签关系映射头文件
#include "Animation/LyraAnimInstance.h" // 包含Lyra动画实例头文件
#include "Engine/World.h" // 包含引擎世界头文件
#include "GameFramework/Pawn.h" // 包含Pawn类头文件
#include "LyraGlobalAbilitySystem.h" // 包含Lyra全局能力系统头文件
#include "LyraLogChannels.h" // 包含Lyra日志频道头文件
#include "System/LyraAssetManager.h" // 包含Lyra资源管理器头文件
#include "System/LyraGameData.h" // 包含Lyra游戏数据头文件

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraAbilitySystemComponent) // 包含UE生成的inline代码

// 定义游戏标签：能力输入被阻塞
UE_DEFINE_GAMEPLAY_TAG(TAG_Gameplay_AbilityInputBlocked, "Gameplay.AbilityInputBlocked");

/**
 * ULyraAbilitySystemComponent构造函数
 * @param ObjectInitializer - 对象初始化器，用于UE属性系统初始化
 */
ULyraAbilitySystemComponent::ULyraAbilitySystemComponent(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer) // 调用父类构造函数
{
	InputPressedSpecHandles.Reset(); // 重置输入按下的能力规格句柄数组
	InputReleasedSpecHandles.Reset(); // 重置输入释放的能力规格句柄数组
	InputHeldSpecHandles.Reset(); // 重置输入按住的能力规格句柄数组

	FMemory::Memset(ActivationGroupCounts, 0, sizeof(ActivationGroupCounts)); // 将激活组计数数组初始化为0
}

/**
 * 结束游戏时的清理操作
 * @param EndPlayReason - 结束游戏的原因枚举
 */
void ULyraAbilitySystemComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	// 获取全局能力系统并取消注册当前ASC
	if (ULyraGlobalAbilitySystem* GlobalAbilitySystem = UWorld::GetSubsystem<ULyraGlobalAbilitySystem>(GetWorld()))
	{
		GlobalAbilitySystem->UnregisterASC(this); // 从全局系统取消注册
	}

	Super::EndPlay(EndPlayReason); // 调用父类的EndPlay方法
}

/**
 * 初始化能力拥有者和化身角色信息
 * @param InOwnerActor - 拥有者Actor指针
 * @param InAvatarActor - 化身Actor指针
 */
void ULyraAbilitySystemComponent::InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor)
{
	FGameplayAbilityActorInfo* ActorInfo = AbilityActorInfo.Get(); // 获取能力Actor信息
	check(ActorInfo); // 检查ActorInfo是否有效
	check(InOwnerActor); // 检查InOwnerActor是否有效

	// 检查是否有新的Pawn化身
	const bool bHasNewPawnAvatar = Cast<APawn>(InAvatarActor) && (InAvatarActor != ActorInfo->AvatarActor);

	Super::InitAbilityActorInfo(InOwnerActor, InAvatarActor); // 调用父类的初始化方法

	if (bHasNewPawnAvatar) // 如果有新的Pawn化身
	{
		// 通知所有能力设置了新的Pawn化身
		for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) // 遍历所有可激活能力
		{
PRAGMA_DISABLE_DEPRECATION_WARNINGS // 禁用弃用警告
			// 确保所有能力都是实例化的
			ensureMsgf(AbilitySpec.Ability && AbilitySpec.Ability->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced, TEXT("InitAbilityActorInfo: All Abilities should be Instanced (NonInstanced is being deprecated due to usability issues)."));
PRAGMA_ENABLE_DEPRECATION_WARNINGS // 启用弃用警告
	
			TArray<UGameplayAbility*> Instances = AbilitySpec.GetAbilityInstances(); // 获取能力实例数组
			for (UGameplayAbility* AbilityInstance : Instances) // 遍历所有能力实例
			{
				ULyraGameplayAbility* LyraAbilityInstance = Cast<ULyraGameplayAbility>(AbilityInstance); // 转换为Lyra能力实例
				if (LyraAbilityInstance) // 如果转换成功
				{
					// 能力实例可能在回放中缺失
					LyraAbilityInstance->OnPawnAvatarSet(); // 调用Pawn化身设置回调
				}
			}
		}

		// 当我们实际有Pawn化身时注册到全局系统。我们等到这个时候，因为一些全局应用的效果可能需要化身。
		if (ULyraGlobalAbilitySystem* GlobalAbilitySystem = UWorld::GetSubsystem<ULyraGlobalAbilitySystem>(GetWorld())) // 获取全局能力系统
		{
			GlobalAbilitySystem->RegisterASC(this); // 注册到全局系统
		}

		// 初始化动画实例与能力系统
		if (ULyraAnimInstance* LyraAnimInst = Cast<ULyraAnimInstance>(ActorInfo->GetAnimInstance())) // 获取Lyra动画实例
		{
			LyraAnimInst->InitializeWithAbilitySystem(this); // 使用能力系统初始化动画实例
		}

		TryActivateAbilitiesOnSpawn(); // 尝试在生成时激活能力
	}
}

/**
 * 尝试在生成时激活能力
 */
void ULyraAbilitySystemComponent::TryActivateAbilitiesOnSpawn()
{
	ABILITYLIST_SCOPE_LOCK(); // 能力列表范围锁，防止竞争条件
	for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) // 遍历所有可激活能力
	{
		if (const ULyraGameplayAbility* LyraAbilityCDO = Cast<ULyraGameplayAbility>(AbilitySpec.Ability)) // 转换为Lyra能力CDO
		{
			LyraAbilityCDO->TryActivateAbilityOnSpawn(AbilityActorInfo.Get(), AbilitySpec); // 尝试在生成时激活能力
		}
	}
}

/**
 * 根据函数条件取消能力
 * @param ShouldCancelFunc - 判断函数，返回true表示应该取消该能力
 * @param bReplicateCancelAbility - 是否复制取消操作到网络客户端
 */
void ULyraAbilitySystemComponent::CancelAbilitiesByFunc(TShouldCancelAbilityFunc ShouldCancelFunc, bool bReplicateCancelAbility)
{
	ABILITYLIST_SCOPE_LOCK(); // 能力列表范围锁
	for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) // 遍历所有可激活能力
	{
		if (!AbilitySpec.IsActive()) // 如果能力不活跃，跳过
		{
			continue;
		}

		ULyraGameplayAbility* LyraAbilityCDO = Cast<ULyraGameplayAbility>(AbilitySpec.Ability); // 转换为Lyra能力CDO
		if (!LyraAbilityCDO) // 如果转换失败
		{
			UE_LOG(LogLyraAbilitySystem, Error, TEXT("CancelAbilitiesByFunc: Non-LyraGameplayAbility %s was Granted to ASC. Skipping."), *AbilitySpec.Ability.GetName()); // 记录错误日志
			continue;
		}

PRAGMA_DISABLE_DEPRECATION_WARNINGS // 禁用弃用警告
		// 确保所有能力都是实例化的
		ensureMsgf(AbilitySpec.Ability->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced, TEXT("CancelAbilitiesByFunc: All Abilities should be Instanced (NonInstanced is being deprecated due to usability issues)."));
PRAGMA_ENABLE_DEPRECATION_WARNINGS // 启用弃用警告
			
		// 取消所有生成的实例
		TArray<UGameplayAbility*> Instances = AbilitySpec.GetAbilityInstances(); // 获取能力实例数组
		for (UGameplayAbility* AbilityInstance : Instances) // 遍历所有能力实例
		{
			ULyraGameplayAbility* LyraAbilityInstance = CastChecked<ULyraGameplayAbility>(AbilityInstance); // 转换为Lyra能力实例

			if (ShouldCancelFunc(LyraAbilityInstance, AbilitySpec.Handle)) // 如果应该取消该能力
			{
				if (LyraAbilityInstance->CanBeCanceled()) // 如果能力可以被取消
				{
					LyraAbilityInstance->CancelAbility(AbilitySpec.Handle, AbilityActorInfo.Get(), LyraAbilityInstance->GetCurrentActivationInfo(), bReplicateCancelAbility); // 取消能力
				}
				else // 如果能力不能被取消
				{
					UE_LOG(LogLyraAbilitySystem, Error, TEXT("CancelAbilitiesByFunc: Can't cancel ability [%s] because CanBeCanceled is false."), *LyraAbilityInstance->GetName()); // 记录错误日志
				}
			}
		}
	}
}

/**
 * 取消输入激活的能力
 * @param bReplicateCancelAbility - 是否复制取消操作到网络客户端
 */
void ULyraAbilitySystemComponent::CancelInputActivatedAbilities(bool bReplicateCancelAbility)
{
	// 定义判断函数：取消输入触发或输入激活的能力
	auto ShouldCancelFunc = [this](const ULyraGameplayAbility* LyraAbility, FGameplayAbilitySpecHandle Handle)
	{
		const ELyraAbilityActivationPolicy ActivationPolicy = LyraAbility->GetActivationPolicy(); // 获取能力激活策略
		return ((ActivationPolicy == ELyraAbilityActivationPolicy::OnInputTriggered) || (ActivationPolicy == ELyraAbilityActivationPolicy::WhileInputActive)); // 返回是否应该取消
	};

	CancelAbilitiesByFunc(ShouldCancelFunc, bReplicateCancelAbility); // 调用取消能力函数
}

/**
 * 能力规格输入按下处理
 * @param Spec - 能力规格引用
 */
void ULyraAbilitySystemComponent::AbilitySpecInputPressed(FGameplayAbilitySpec& Spec)
{
	Super::AbilitySpecInputPressed(Spec); // 调用父类的输入按下处理

	// 我们不支持UGameplayAbility::bReplicateInputDirectly
	// 使用复制事件代替，这样WaitInputPress能力任务可以工作
	if (Spec.IsActive()) // 如果能力是活跃的
	{
PRAGMA_DISABLE_DEPRECATION_WARNINGS // 禁用弃用警告
		const UGameplayAbility* Instance = Spec.GetPrimaryInstance(); // 获取主要能力实例
		FPredictionKey OriginalPredictionKey = Instance ? Instance->GetCurrentActivationInfo().GetActivationPredictionKey() : Spec.ActivationInfo.GetActivationPredictionKey(); // 获取预测键
PRAGMA_ENABLE_DEPRECATION_WARNINGS // 启用弃用警告

		// 调用InputPressed事件。这里不复制。如果有人监听，他们可能将InputPressed事件复制到服务器
		InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputPressed, Spec.Handle, OriginalPredictionKey); // 调用复制事件
	}
}

/**
 * 能力规格输入释放处理
 * @param Spec - 能力规格引用
 */
void ULyraAbilitySystemComponent::AbilitySpecInputReleased(FGameplayAbilitySpec& Spec)
{
	Super::AbilitySpecInputReleased(Spec); // 调用父类的输入释放处理

	// 我们不支持UGameplayAbility::bReplicateInputDirectly
	// 使用复制事件代替，这样WaitInputRelease能力任务可以工作
	if (Spec.IsActive()) // 如果能力是活跃的
	{
PRAGMA_DISABLE_DEPRECATION_WARNINGS // 禁用弃用警告
		const UGameplayAbility* Instance = Spec.GetPrimaryInstance(); // 获取主要能力实例
		FPredictionKey OriginalPredictionKey = Instance ? Instance->GetCurrentActivationInfo().GetActivationPredictionKey() : Spec.ActivationInfo.GetActivationPredictionKey(); // 获取预测键
PRAGMA_ENABLE_DEPRECATION_WARNINGS // 启用弃用警告

		// 调用InputReleased事件。这里不复制。如果有人监听，他们可能将InputReleased事件复制到服务器
		InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::InputReleased, Spec.Handle, OriginalPredictionKey); // 调用复制事件
	}
}

/**
 * 处理能力输入标签按下
 * @param InputTag - 输入的游戏标签
 */
void ULyraAbilitySystemComponent::AbilityInputTagPressed(const FGameplayTag& InputTag)
{
	if (InputTag.IsValid()) // 如果输入标签有效
	{
		for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) // 遍历所有可激活能力
		{
			if (AbilitySpec.Ability && (AbilitySpec.GetDynamicSpecSourceTags().HasTagExact(InputTag))) // 如果能力存在且具有匹配的输入标签
			{
				InputPressedSpecHandles.AddUnique(AbilitySpec.Handle); // 添加到输入按下句柄数组
				InputHeldSpecHandles.AddUnique(AbilitySpec.Handle); // 添加到输入按住句柄数组
			}
		}
	}
}

/**
 * 处理能力输入标签释放
 * @param InputTag - 输入的游戏标签
 */
void ULyraAbilitySystemComponent::AbilityInputTagReleased(const FGameplayTag& InputTag)
{
	if (InputTag.IsValid()) // 如果输入标签有效
	{
		for (const FGameplayAbilitySpec& AbilitySpec : ActivatableAbilities.Items) // 遍历所有可激活能力
		{
			if (AbilitySpec.Ability && (AbilitySpec.GetDynamicSpecSourceTags().HasTagExact(InputTag))) // 如果能力存在且具有匹配的输入标签
			{
				InputReleasedSpecHandles.AddUnique(AbilitySpec.Handle); // 添加到输入释放句柄数组
				InputHeldSpecHandles.Remove(AbilitySpec.Handle); // 从输入按住句柄数组移除
			}
		}
	}
}

/**
 * 处理能力输入
 * @param DeltaTime - 帧时间差
 * @param bGamePaused - 游戏是否暂停
 */
void ULyraAbilitySystemComponent::ProcessAbilityInput(float DeltaTime, bool bGamePaused)
{
	// 如果能力输入被阻塞，清除输入并返回
	if (HasMatchingGameplayTag(TAG_Gameplay_AbilityInputBlocked))
	{
		ClearAbilityInput(); // 清除能力输入
		return;
	}

	static TArray<FGameplayAbilitySpecHandle> AbilitiesToActivate; // 静态数组，存储要激活的能力句柄
	AbilitiesToActivate.Reset(); // 重置数组

	//@TODO: 查看是否可以在某些循环中使用FScopedServerAbilityRPCBatcher ScopedRPCBatcher

	//
	// 处理所有在输入按住时激活的能力
	//
	for (const FGameplayAbilitySpecHandle& SpecHandle : InputHeldSpecHandles) // 遍历输入按住的能力句柄
	{
		if (const FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle)) // 根据句柄查找能力规格
		{
			if (AbilitySpec->Ability && !AbilitySpec->IsActive()) // 如果能力存在且不活跃
			{
				const ULyraGameplayAbility* LyraAbilityCDO = Cast<ULyraGameplayAbility>(AbilitySpec->Ability); // 转换为Lyra能力CDO
				if (LyraAbilityCDO && LyraAbilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::WhileInputActive) // 如果是输入激活策略
				{
					AbilitiesToActivate.AddUnique(AbilitySpec->Handle); // 添加到要激活的数组
				}
			}
		}
	}

	//
	// 处理所有这一帧输入被按下的能力
	//
	for (const FGameplayAbilitySpecHandle& SpecHandle : InputPressedSpecHandles) // 遍历输入按下的能力句柄
	{
		if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle)) // 根据句柄查找能力规格
		{
			if (AbilitySpec->Ability) // 如果能力存在
			{
				AbilitySpec->InputPressed = true; // 设置输入按下标志

				if (AbilitySpec->IsActive()) // 如果能力是活跃的
				{
					// 能力是活跃的，所以传递输入事件
					AbilitySpecInputPressed(*AbilitySpec); // 调用能力规格输入按下
				}
				else // 如果能力不活跃
				{
					const ULyraGameplayAbility* LyraAbilityCDO = Cast<ULyraGameplayAbility>(AbilitySpec->Ability); // 转换为Lyra能力CDO

					if (LyraAbilityCDO && LyraAbilityCDO->GetActivationPolicy() == ELyraAbilityActivationPolicy::OnInputTriggered) // 如果是输入触发策略
					{
						AbilitiesToActivate.AddUnique(AbilitySpec->Handle); // 添加到要激活的数组
					}
				}
			}
		}
	}

	//
	// 尝试激活所有来自按下和按住的能力
	// 我们一次性完成，这样按住输入不会激活能力
	// 然后也因为按下而发送输入事件给能力
	//
	for (const FGameplayAbilitySpecHandle& AbilitySpecHandle : AbilitiesToActivate) // 遍历要激活的能力句柄
	{
		TryActivateAbility(AbilitySpecHandle); // 尝试激活能力
	}

	//
	// 处理所有这一帧输入被释放的能力
	//
	for (const FGameplayAbilitySpecHandle& SpecHandle : InputReleasedSpecHandles) // 遍历输入释放的能力句柄
	{
		if (FGameplayAbilitySpec* AbilitySpec = FindAbilitySpecFromHandle(SpecHandle)) // 根据句柄查找能力规格
		{
			if (AbilitySpec->Ability) // 如果能力存在
			{
				AbilitySpec->InputPressed = false; // 设置输入按下标志为false

				if (AbilitySpec->IsActive()) // 如果能力是活跃的
				{
					// 能力是活跃的，所以传递输入事件
					AbilitySpecInputReleased(*AbilitySpec); // 调用能力规格输入释放
				}
			}
		}
	}

	//
	// 清除缓存的能力句柄
	//
	InputPressedSpecHandles.Reset(); // 重置输入按下句柄数组
	InputReleasedSpecHandles.Reset(); // 重置输入释放句柄数组
}

/**
 * 清除能力输入状态
 */
void ULyraAbilitySystemComponent::ClearAbilityInput()
{
	InputPressedSpecHandles.Reset(); // 重置输入按下句柄数组
	InputReleasedSpecHandles.Reset(); // 重置输入释放句柄数组
	InputHeldSpecHandles.Reset(); // 重置输入按住句柄数组
}

/**
 * 通知能力激活
 * @param Handle - 能力规格句柄
 * @param Ability - 游戏能力指针
 */
void ULyraAbilitySystemComponent::NotifyAbilityActivated(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability)
{
	Super::NotifyAbilityActivated(Handle, Ability); // 调用父类的通知能力激活

	if (ULyraGameplayAbility* LyraAbility = Cast<ULyraGameplayAbility>(Ability)) // 转换为Lyra能力
	{
		AddAbilityToActivationGroup(LyraAbility->GetActivationGroup(), LyraAbility); // 添加到激活组
	}
}

/**
 * 通知能力激活失败
 * @param Handle - 能力规格句柄
 * @param Ability - 游戏能力指针
 * @param FailureReason - 失败原因标签容器
 */
void ULyraAbilitySystemComponent::NotifyAbilityFailed(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
{
	Super::NotifyAbilityFailed(Handle, Ability, FailureReason); // 调用父类的通知能力失败

	if (APawn* Avatar = Cast<APawn>(GetAvatarActor())) // 获取化身Pawn
	{
		// 如果不是本地控制且能力支持网络，通知客户端
		if (!Avatar->IsLocallyControlled() && Ability->IsSupportedForNetworking())
		{
			ClientNotifyAbilityFailed(Ability, FailureReason); // 客户端通知能力失败
			return;
		}
	}

	HandleAbilityFailed(Ability, FailureReason); // 处理能力失败
}

/**
 * 通知能力结束
 * @param Handle - 能力规格句柄
 * @param Ability - 游戏能力指针
 * @param bWasCancelled - 是否被取消
 */
void ULyraAbilitySystemComponent::NotifyAbilityEnded(FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, bool bWasCancelled)
{
	Super::NotifyAbilityEnded(Handle, Ability, bWasCancelled); // 调用父类的通知能力结束

	if (ULyraGameplayAbility* LyraAbility = Cast<ULyraGameplayAbility>(Ability)) // 转换为Lyra能力
	{
		RemoveAbilityFromActivationGroup(LyraAbility->GetActivationGroup(), LyraAbility); // 从激活组移除
	}
}

/**
 * 应用能力阻塞和取消标签
 * @param AbilityTags - 能力标签容器
 * @param RequestingAbility - 请求能力指针
 * @param bEnableBlockTags - 是否启用阻塞标签
 * @param BlockTags - 阻塞标签容器
 * @param bExecuteCancelTags - 是否执行取消标签
 * @param CancelTags - 取消标签容器
 */
void ULyraAbilitySystemComponent::ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer& BlockTags, bool bExecuteCancelTags, const FGameplayTagContainer& CancelTags)
{
	FGameplayTagContainer ModifiedBlockTags = BlockTags; // 修改后的阻塞标签
	FGameplayTagContainer ModifiedCancelTags = CancelTags; // 修改后的取消标签

	if (TagRelationshipMapping) // 如果标签关系映射存在
	{
		// 使用映射将能力标签扩展为阻塞和取消标签
		TagRelationshipMapping->GetAbilityTagsToBlockAndCancel(AbilityTags, &ModifiedBlockTags, &ModifiedCancelTags); // 获取要阻塞和取消的标签
	}

	Super::ApplyAbilityBlockAndCancelTags(AbilityTags, RequestingAbility, bEnableBlockTags, ModifiedBlockTags, bExecuteCancelTags, ModifiedCancelTags); // 调用父类方法

	//@TODO: 应用任何特殊逻辑，如阻塞输入或移动
}

/**
 * 处理能力可取消状态变化
 * @param AbilityTags - 能力标签容器
 * @param RequestingAbility - 请求能力指针
 * @param bCanBeCanceled - 是否可被取消
 */
void ULyraAbilitySystemComponent::HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bCanBeCanceled)
{
	Super::HandleChangeAbilityCanBeCanceled(AbilityTags, RequestingAbility, bCanBeCanceled); // 调用父类方法

	//@TODO: 应用任何特殊逻辑，如阻塞输入或移动
}

/**
 * 查看能力标签并收集额外的需求和阻塞标签
 * @param AbilityTags - 能力标签容器
 * @param OutActivationRequired - 输出的激活需求标签容器
 * @param OutActivationBlocked - 输出的激活阻塞标签容器
 */
void ULyraAbilitySystemComponent::GetAdditionalActivationTagRequirements(const FGameplayTagContainer& AbilityTags, FGameplayTagContainer& OutActivationRequired, FGameplayTagContainer& OutActivationBlocked) const
{
	if (TagRelationshipMapping) // 如果标签关系映射存在
	{
		TagRelationshipMapping->GetRequiredAndBlockedActivationTags(AbilityTags, &OutActivationRequired, &OutActivationBlocked); // 获取需求和阻塞的激活标签
	}
}

/**
 * 设置当前的标签关系映射，如果为null则清除
 * @param NewMapping - 新的标签关系映射对象指针
 */
void ULyraAbilitySystemComponent::SetTagRelationshipMapping(ULyraAbilityTagRelationshipMapping* NewMapping)
{
	TagRelationshipMapping = NewMapping; // 设置标签关系映射
}

/**
 * 通知客户端能力激活失败（客户端RPC实现）
 * @param Ability - 游戏能力指针
 * @param FailureReason - 失败原因标签容器
 */
void ULyraAbilitySystemComponent::ClientNotifyAbilityFailed_Implementation(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
{
	HandleAbilityFailed(Ability, FailureReason); // 处理能力失败
}

/**
 * 处理能力失败
 * @param Ability - 游戏能力指针
 * @param FailureReason - 失败原因标签容器
 */
void ULyraAbilitySystemComponent::HandleAbilityFailed(const UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason)
{
	//UE_LOG(LogLyraAbilitySystem, Warning, TEXT("Ability %s failed to activate (tags: %s)"), *GetPathNameSafe(Ability), *FailureReason.ToString()); // 记录警告日志

	if (const ULyraGameplayAbility* LyraAbility = Cast<const ULyraGameplayAbility>(Ability)) // 转换为Lyra能力
	{
		LyraAbility->OnAbilityFailedToActivate(FailureReason); // 调用能力激活失败回调
	}	
}

/**
 * 检查激活组是否被阻塞
 * @param Group - 激活组枚举
 * @return bool - 返回该组是否被阻塞
 */
bool ULyraAbilitySystemComponent::IsActivationGroupBlocked(ELyraAbilityActivationGroup Group) const
{
	bool bBlocked = false; // 阻塞标志

	switch (Group) // 根据激活组判断
	{
	case ELyraAbilityActivationGroup::Independent: // 独立组
		// 独立能力永远不会被阻塞
		bBlocked = false;
		break;

	case ELyraAbilityActivationGroup::Exclusive_Replaceable: // 可替换的独占组
	case ELyraAbilityActivationGroup::Exclusive_Blocking: // 阻塞的独占组
		// 独占能力可以在没有东西阻塞时激活
		bBlocked = (ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::Exclusive_Blocking] > 0); // 检查阻塞独占组计数
		break;

	default:
		checkf(false, TEXT("IsActivationGroupBlocked: Invalid ActivationGroup [%d]\n"), (uint8)Group); // 检查失败，无效的激活组
		break;
	}

	return bBlocked; // 返回阻塞状态
}

/**
 * 添加能力到激活组
 * @param Group - 激活组枚举
 * @param LyraAbility - Lyra能力指针
 */
void ULyraAbilitySystemComponent::AddAbilityToActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility)
{
	check(LyraAbility); // 检查LyraAbility是否有效
	check(ActivationGroupCounts[(uint8)Group] < INT32_MAX); // 检查激活组计数是否未溢出

	ActivationGroupCounts[(uint8)Group]++; // 增加激活组计数

	const bool bReplicateCancelAbility = false; // 不复制取消能力操作

	switch (Group) // 根据激活组处理
	{
	case ELyraAbilityActivationGroup::Independent: // 独立组
		// 独立能力不取消任何其他能力
		break;

	case ELyraAbilityActivationGroup::Exclusive_Replaceable: // 可替换的独占组
	case ELyraAbilityActivationGroup::Exclusive_Blocking: // 阻塞的独占组
		CancelActivationGroupAbilities(ELyraAbilityActivationGroup::Exclusive_Replaceable, LyraAbility, bReplicateCancelAbility); // 取消可替换独占组的能力
		break;

	default:
		checkf(false, TEXT("AddAbilityToActivationGroup: Invalid ActivationGroup [%d]\n"), (uint8)Group); // 检查失败，无效的激活组
		break;
	}

	// 确保最多只有一个独占能力在运行
	const int32 ExclusiveCount = ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::Exclusive_Replaceable] + ActivationGroupCounts[(uint8)ELyraAbilityActivationGroup::Exclusive_Blocking]; // 计算独占能力总数
	if (!ensure(ExclusiveCount <= 1)) // 确保不超过一个
	{
		UE_LOG(LogLyraAbilitySystem, Error, TEXT("AddAbilityToActivationGroup: Multiple exclusive abilities are running.")); // 记录错误日志
	}
}

/**
 * 从激活组移除能力
 * @param Group - 激活组枚举
 * @param LyraAbility - Lyra能力指针
 */
void ULyraAbilitySystemComponent::RemoveAbilityFromActivationGroup(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* LyraAbility)
{
	check(LyraAbility); // 检查LyraAbility是否有效
	check(ActivationGroupCounts[(uint8)Group] > 0); // 检查激活组计数是否大于0

	ActivationGroupCounts[(uint8)Group]--; // 减少激活组计数
}

/**
 * 取消激活组中的能力
 * @param Group - 激活组枚举
 * @param IgnoreLyraAbility - 要忽略的Lyra能力指针
 * @param bReplicateCancelAbility - 是否复制取消操作到网络客户端
 */
void ULyraAbilitySystemComponent::CancelActivationGroupAbilities(ELyraAbilityActivationGroup Group, ULyraGameplayAbility* IgnoreLyraAbility, bool bReplicateCancelAbility)
{
	// 定义判断函数：取消指定组中除了忽略能力之外的所有能力
	auto ShouldCancelFunc = [this, Group, IgnoreLyraAbility](const ULyraGameplayAbility* LyraAbility, FGameplayAbilitySpecHandle Handle)
	{
		return ((LyraAbility->GetActivationGroup() == Group) && (LyraAbility != IgnoreLyraAbility)); // 返回是否应该取消
	};

	CancelAbilitiesByFunc(ShouldCancelFunc, bReplicateCancelAbility); // 调用取消能力函数
}

/**
 * 使用游戏效果添加指定的动态授予标签
 * @param Tag - 要添加的游戏标签
 */
void ULyraAbilitySystemComponent::AddDynamicTagGameplayEffect(const FGameplayTag& Tag)
{
	// 获取动态标签游戏效果类
	const TSubclassOf<UGameplayEffect> DynamicTagGE = ULyraAssetManager::GetSubclass(ULyraGameData::Get().DynamicTagGameplayEffect);
	if (!DynamicTagGE) // 如果找不到游戏效果类
	{
		UE_LOG(LogLyraAbilitySystem, Warning, TEXT("AddDynamicTagGameplayEffect: Unable to find DynamicTagGameplayEffect [%s]."), *ULyraGameData::Get().DynamicTagGameplayEffect.GetAssetName()); // 记录警告日志
		return;
	}

	const FGameplayEffectSpecHandle SpecHandle = MakeOutgoingSpec(DynamicTagGE, 1.0f, MakeEffectContext()); // 创建传出效果规格
	FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); // 获取效果规格指针

	if (!Spec) // 如果效果规格无效
	{
		UE_LOG(LogLyraAbilitySystem, Warning, TEXT("AddDynamicTagGameplayEffect: Unable to make outgoing spec for [%s]."), *GetNameSafe(DynamicTagGE)); // 记录警告日志
		return;
	}

	Spec->DynamicGrantedTags.AddTag(Tag); // 添加动态授予标签

	ApplyGameplayEffectSpecToSelf(*Spec); // 应用游戏效果到自身
}

/**
 * 移除用于添加指定动态授予标签的所有活跃游戏效果实例
 * @param Tag - 要移除的游戏标签
 */
void ULyraAbilitySystemComponent::RemoveDynamicTagGameplayEffect(const FGameplayTag& Tag)
{
	// 获取动态标签游戏效果类
	const TSubclassOf<UGameplayEffect> DynamicTagGE = ULyraAssetManager::GetSubclass(ULyraGameData::Get().DynamicTagGameplayEffect);
	if (!DynamicTagGE) // 如果找不到游戏效果类
	{
		UE_LOG(LogLyraAbilitySystem, Warning, TEXT("RemoveDynamicTagGameplayEffect: Unable to find gameplay effect [%s]."), *ULyraGameData::Get().DynamicTagGameplayEffect.GetAssetName()); // 记录警告日志
		return;
	}

	// 创建游戏效果查询，匹配任何拥有指定标签的效果
	FGameplayEffectQuery Query = FGameplayEffectQuery::MakeQuery_MatchAnyOwningTags(FGameplayTagContainer(Tag));
	Query.EffectDefinition = DynamicTagGE; // 设置效果定义

	RemoveActiveEffects(Query); // 移除活跃效果
}

/**
 * 获取与给定能力句柄和激活信息相关的能力目标数据
 * @param AbilityHandle - 能力规格句柄
 * @param ActivationInfo - 能力激活信息
 * @param OutTargetDataHandle - 输出的目标数据句柄
 */
void ULyraAbilitySystemComponent::GetAbilityTargetData(const FGameplayAbilitySpecHandle AbilityHandle, FGameplayAbilityActivationInfo ActivationInfo, FGameplayAbilityTargetDataHandle& OutTargetDataHandle)
{
	// 在能力目标数据映射中查找对应的复制数据
	TSharedPtr<FAbilityReplicatedDataCache> ReplicatedData = AbilityTargetDataMap.Find(FGameplayAbilitySpecHandleAndPredictionKey(AbilityHandle, ActivationInfo.GetActivationPredictionKey()));
	if (ReplicatedData.IsValid()) // 如果复制数据有效
	{
		OutTargetDataHandle = ReplicatedData->TargetData; // 设置输出目标数据句柄
	}
}